﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;
using TeamsPortal.Configuration;
using TeamsPortal.DataAccess;
using TeamsPortal.ServiceClient;
using TeamsPortal.Web.Controllers.Filters;
using TeamsPortal.Web.Controllers.Models;

namespace TeamsPortal.Web.Api
{
    public class ImageController : ApiController
    {
        private readonly IFileStorageService _fileStorage;
        private readonly IImageService _imageService;
        private readonly IUsersServiceClient _userService;
        private readonly Dictionary<string, string> _extensions = new Dictionary<string,string>();
        private readonly int MaxAvatarHeight = SiteConfiguration.Current.UI.MaxAvatarHeight;
        private readonly int MaxAvatarWidth = SiteConfiguration.Current.UI.MaxAvatarWidth;

        public ImageController(IFileStorageService fileStorage, IImageService imageService, IUsersServiceClient userService)
        {
            _fileStorage = fileStorage;
            _imageService = imageService;
            _userService = userService;

            _extensions.Add(".jpg", "image/jpg");
            _extensions.Add(".png", "image/png");
        }

        //todo: check file size
        [RequireAuthorization]
        public HttpResponseMessage PostAvatar(UploadImageModel model)
        {
            //_roleService.IsUserInRole(User.Identity.Name, UserRoles.Administrators);

            if (ModelState.IsValid)
            {
                Bitmap original = null;
                var name = "newimagefile";
                var errorField = string.Empty;

                if (model.ImageBytes != null)
                {
                    errorField = "File";
                    name = User.Identity.Name;
                    original = Image.FromStream(new MemoryStream(model.ImageBytes)) as Bitmap;
                }

                //If we had success so far
                if (original != null)
                {
                    int width = model.Width == 0 ? original.Width : model.Width;
                    int height = model.Height == 0 ? original.Height : model.Height;
                    Bitmap img = createImage(original, model.X, model.Y, width, height);

                    int newHeight = height;
                    int newWidth = width;
                    if (height > MaxAvatarHeight || width > MaxAvatarWidth)
                    {
                        // Figure out the ratio
                        double ratioX = (double)MaxAvatarWidth / (double)width;
                        double ratioY = (double)MaxAvatarHeight / (double)height;
                        // use whichever multiplier is smaller
                        double ratio = ratioX < ratioY ? ratioX : ratioY;
                        // now we can get the new height and width
                        newHeight = Convert.ToInt32(height * ratio);
                        newWidth = Convert.ToInt32(width * ratio);
                    }

                    Image thumbnail = img.GetThumbnailImage(newWidth, newHeight, () => true, new IntPtr());
                    
                    User user = _userService.GetByName(User.Identity.Name);
                    _imageService.SetAvatar(thumbnail, user);

                    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Moved);
                    response.Headers.Location = new Uri(model.RedirectUrl, UriKind.Relative);
                    
                    return response;
                }
                else //Otherwise we add an error and return to the (previous) view with the model data
                {
                    ModelState.AddModelError(errorField,
                                             "Your upload did not seem valid. Please try again using only correct images!");
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                }
            }
            else
                return Request.CreateResponse(HttpStatusCode.BadRequest);
        }

        public HttpResponseMessage Get(int id)
        {
            ImageInfo imgInfo = _imageService.Get(id);
            if (imgInfo == null) {
                return new HttpResponseMessage(HttpStatusCode.NotFound);
            }
            Stream imgStream = _fileStorage.LoadStream(imgInfo.Path);

            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(imgStream)
            };

            // Find the MIME type
            string mimeType = _extensions[Path.GetExtension(imgInfo.Path)];
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);

            return response;
        }

        /// <summary>
        /// Creates a small image out of a larger image.
        /// </summary>
        /// <param name="original">The original image which should be cropped (will remain untouched).</param>
        /// <param name="x">The value where to start on the x axis.</param>
        /// <param name="y">The value where to start on the y axis.</param>
        /// <param name="width">The width of the final image.</param>
        /// <param name="height">The height of the final image.</param>
        /// <returns>The cropped image.</returns>
        private Bitmap createImage(Bitmap original, int x, int y, int width, int height)
        {
            var img = new Bitmap(width, height);

            using (Graphics g = Graphics.FromImage(img))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(original, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
            }

            return img;
        }
    }
}
